import { reactive, ref } from 'vue';
import dayjs from 'dayjs';
import { ElMessage, ElMessageBox } from 'element-plus';

type PageChangeFunc = (val: number) => void;

interface SortParam {
  sortType?: 'asc' | 'desc' | null | undefined;
  sortProp?: string
}

export interface IUseTableOptions {
  // 是否手动请求
  manual: boolean;
  defaultSort?: SortParam
}

export interface TableData<T> {
  list: T[];
  total: number;
}

export interface PaginationProps {
  pageCount: number;
  page: number;
  pageSize: number;
  layout: string;
  pageSizes: number[];
  onCurrentPageChange: PageChangeFunc;
  onPageSizeChange: PageChangeFunc;
}

export function useTable<T>(
  requestApi: (...args: any) => Promise<TableData<T>>,
  options: IUseTableOptions = { manual: false }
) {
  const { manual } = options;
  const loading = ref(false);
  const error = ref(null);
  const tableData = reactive<TableData<T>>({
    list: [],
    total: 0,
  });

  const pagination = reactive<PaginationProps>({
    pageCount: 5,
    page: 1,
    pageSize: 20,
    layout: 'total, sizes, prev, pager, next, jumper',
    pageSizes: [10, 20, 30, 50],
    onCurrentPageChange: (val: number) => {
      pagination.page = val;
      refresh();
    },
    onPageSizeChange: (val: number) => {
      pagination.pageSize = val;
      refresh();
    },
  });

  const sortParam = reactive<SortParam>({
    sortProp: options?.defaultSort?.sortProp,
    sortType: options?.defaultSort?.sortType
  })

  const resetPage = () => {
    pagination.page = 1;
  };

  const run = manual ? (params?: object) => refresh(params) : null;

  const resetAndRefresh = () => {
    pagination.page = 1;
    tableData.list = [];
    tableData.total = 0;
    refresh();
  };

  const refresh = (params?: any) => {
    loading.value = true;
    const _param = { page: pagination.page, pageSize: pagination.pageSize, ...params }
    if (sortParam.sortType) {
      _param['sort'] = sortParam
    } else {
      _param['sort'] = {}
    }

    requestApi(_param)
      .then((res) => {
        tableData.list = reactive(
          res.list.map((item) => {
            return {
              ...item,
              created_at: dayjs((item as any).created_at).format('YYYY-MM-DD HH:mm:ss'),
              updated_at: dayjs((item as any).updated_at).format('YYYY-MM-DD HH:mm:ss'),
            };
          })
        );
        tableData.total = res.total;
        loading.value = false;
      })
      .catch((err) => {
        console.log(err);
        loading.value = false;
        error.value = err;
      });
  };

  const createRemoveHandler =
    (removeFn: (row: T) => Promise<any>) =>
      (row: T): void => {
        ElMessageBox.confirm(`删除后不可恢复，是否继续?`, '提示', {
          confirmButtonText: '确认',
          cancelButtonText: '取消',
          type: 'warning',
          beforeClose(action, instance, done) {
            if (action === 'confirm') {
              instance.confirmButtonLoading = true;
              instance.confirmButtonText = '删除中';
              removeFn(row)
                .then(() => {
                  setTimeout(() => {
                    done();
                    instance.confirmButtonLoading = false;
                  });
                })
                .catch(() => {
                  instance.confirmButtonLoading = false;
                  ElMessage.error('删除失败');
                });
            } else {
              done();
            }
          },
        })
          .then(() => {
            ElMessage.success('删除成功');
            refresh();
          })
          .catch(() => {});
      };

  if (!manual) {
    refresh();
  }

  const onSortChange = (value: any) => {
    if (value?.order === 'ascending') {
      sortParam.sortType = 'asc'
    } else if (value?.order === 'descending') {
      sortParam.sortType = 'desc'
    } else {
      sortParam.sortType = null
    }
    sortParam.sortProp = value.prop
    resetAndRefresh()
  }

  return {
    tableData,
    pagination,
    loading,
    error,
    run,
    refresh,
    resetPage,
    resetAndRefresh,
    createRemoveHandler,
    onSortChange,
  };
}
